﻿namespace TestTool.HttpTransport
{
    using System;
    using System.Collections.Generic;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.Xml;
    using TestTool.HttpTransport.Interfaces;
    using TestTool.HttpTransport.MessageEncoding;

    public class ControlledTextMessageBindingElement : MessageEncodingBindingElement, IWsdlExportExtension
    {
        private List<IChannelController> _controllers;
        private string _encoding;
        private string _mediaType;
        private System.ServiceModel.Channels.MessageVersion _msgVersion;
        //private XmlDictionaryReaderQuotas _readerQuotas;

        public ControlledTextMessageBindingElement() : this("utf-8")
        {
        }

        public ControlledTextMessageBindingElement(string encoding) 
            : this(encoding, "application/soap+xml")
        {
        }

        private ControlledTextMessageBindingElement(ControlledTextMessageBindingElement binding) : this(binding.Encoding, binding.MediaType, binding.MessageVersion)
        {
            //this._readerQuotas = new XmlDictionaryReaderQuotas();
            //binding.ReaderQuotas.CopyTo(this._readerQuotas);
            this._controllers = binding._controllers;
        }

        public ControlledTextMessageBindingElement(string encoding, string mediaType) : this(encoding, mediaType, System.ServiceModel.Channels.MessageVersion.Soap12WSAddressing10)
        {
        }

        public ControlledTextMessageBindingElement(string encoding, string mediaType, System.ServiceModel.Channels.MessageVersion msgVersion)
        {
            if (encoding == null)
            {
                throw new ArgumentNullException("encoding");
            }
            if (mediaType == null)
            {
                throw new ArgumentNullException("mediaType");
            }
            if (msgVersion == null)
            {
                throw new ArgumentNullException("msgVersion");
            }
            this._msgVersion = msgVersion;
            this._mediaType = mediaType;
            this._encoding = encoding;
            //this._readerQuotas = new XmlDictionaryReaderQuotas();
            this._controllers = new List<IChannelController>();
        }

        public void AddController(IChannelController controller)
        {
            this._controllers.Add(controller);
        }

        public void AddControllers(IEnumerable<IChannelController> controllers)
        {
            this._controllers.AddRange(controllers);
        }

        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelFactory<TChannel>();
        }

        public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) //where TChannel: class, IChannel
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelListener<TChannel>();
        }

        public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            return context.CanBuildInnerChannelFactory<TChannel>();
        }

        public override bool CanBuildChannelListener<TChannel>(BindingContext context) //where TChannel: class, IChannel
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            context.BindingParameters.Add(this);
            return context.CanBuildInnerChannelListener<TChannel>();
        }

        public override BindingElement Clone()
        {
            return new ControlledTextMessageBindingElement(this);
        }

        public override MessageEncoderFactory CreateMessageEncoderFactory()
        {
            ControlledTextMessageEncoderFactory factory = new ControlledTextMessageEncoderFactory(this.MediaType, this.Encoding, this.MessageVersion);
            ControlledTextMessageEncoder encoder = (ControlledTextMessageEncoder) factory.Encoder;
            encoder.AddControllers(this._controllers);
            encoder.SetBindingElement(this);
            return factory;
        }

        public override T GetProperty<T>(BindingContext context) //where T: class
        {
            //if (typeof(T) == typeof(XmlDictionaryReaderQuotas))
            //{
            //    return (T) this._readerQuotas;
            //}
            return base.GetProperty<T>(context);
        }

        void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
        {
        }

        void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
        {
            TextMessageEncodingBindingElement element = new TextMessageEncodingBindingElement {
                MessageVersion = this._msgVersion
            };
            ((IWsdlExportExtension) element).ExportEndpoint(exporter, context);
        }

        public List<IChannelController> Controllers
        {
            get
            {
                return this._controllers;
            }
        }

        public string Encoding
        {
            get
            {
                return this._encoding;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this._encoding = value;
            }
        }

        public string MediaType
        {
            get
            {
                return this._mediaType;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this._mediaType = value;
            }
        }

        public override System.ServiceModel.Channels.MessageVersion MessageVersion
        {
            get
            {
                return this._msgVersion;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                this._msgVersion = value;
            }
        }

        //public XmlDictionaryReaderQuotas ReaderQuotas
        //{
        //    get
        //    {
        //        return this._readerQuotas;
        //    }
        //}
    }
}

